/**
 * ElementManager.java
 * 
 * @authors: Connor Gordon, Difan Zhao, Kathleen Lan, Patrick Royal
 */

package model;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import utilities.Calculator;


/**
 * Handles the manipulation of lists of elements.
 * 
 * @author Group 8
 * 
 */
public class ElementManager {
    private List<Element> myEls;

    /**
     * Constructor for element manager.
     */
    public ElementManager () {
        myEls = new LinkedList<Element>();
    }

    /**
     * Asks each element to specify its data.
     * @param type type to pass to the elements
     */
    public void specifyData(String type) {
        for (Element e: myEls) {
            e.specifyData(type);
        }
    }

    /**
     * Returns all data in a given range.
     * @param range range of data
     */
    public Map<Element, List<Double>> getRangeOfData(int range) {
        Map<Element, List<Double>> m = new HashMap<Element, List<Double>>();
        for (Element e :myEls) {
            m.put(e, e.getDataRange(range));
        }
        return m;
    }
    /**
     * Add new element.
     * @param e element to be added
     */
    public void addElement (Element e) {
        myEls.add(e);
    }

    /**
     * Returns the element at a given index.
     * @param index index of the element
     */
    public Element getElement (int index) {
        return myEls.get(index);
    }

    /**
     * Returns myEls as an unmodifiable list.
     */
    public List<Element> getUnmodifiableList () {
        return Collections.unmodifiableList(myEls);
    }

    /**
     * Filters a list to only return data matching a given
     * time period.
     * @param start start of the time period
     * @param end end of the time period
     * @param list list of stocks to filter
     */
    public List<Element> filterDataWithTime (int start, int end,
            List<Element> list) {
        for (int j = 0; j < list.size(); j++) {
            List<Double> newValues = new ArrayList<Double>();
            for (int i = start; i < end; i++) {
                newValues.add(list.get(j).getValueList().get(i));
            }
            list.get(j).setValueList(newValues);
        }
        return list;
    }

    /**
     * Filters a list to only return data from a given stock.
     * @param stock stock to filter for
     * @param list list of stocks to filter
     */
    public List<Element> filterDataWithStock (String stock, List<Element> list) {
        List<Element> newList = new ArrayList<Element>();
        for (Element e : list) {
            if (stock.equals(e.getName())) {
                newList.add(e);
            }
        }
        return newList;
    }

    /**
     * Filters a list to only return data matching a given
     * characteristic.
     * @param start lowest value in the characteristic
     * @param end highest value in the characteristic
     * @param list list to be filtered
     */
    public List<Element> filter (double start, double end, List<Element> list) {
        for (int i = 0; i < list.size(); i++) {
            if (start > list.get(i).getValue() || list.get(i).getValue() > end) {
                list.remove(i);
            }
        }
        return list;
    }

    /**
     * Sorts a list numerically from smallest to largest.
     * @param ascending ascending or descending?
     */
    public void sort (boolean ascending) {
        List<Element> sortedList = new ArrayList<Element>();
        while (myEls.size() > 0) {
            int i = 0;
            if (ascending) {
                i = getMin(myEls);
            }
            else {
                i = getMax(myEls);
            }
            sortedList.add(myEls.get(i));
            myEls.remove(i);
        }
        myEls.addAll(sortedList);
    }

    /**
     * Finds the smallest element in the list, by value.
     * @param list list to be sorted
     */
    public int getMin (List<Element> list) {
        int min = 0;
        for (int i = 0; i < list.size(); i++) {
            if (list.get(i).getValue() < list.get(min).getValue()) {
                min = i;
            }
        }
        return min;
    }

    /**
     * Finds the largest element in the list, by value.
     * @param list list of elements to be searched
     */
    public int getMax (List<Element> list) {
        int max = 0;
        for (int i = 0; i < list.size(); i++) {
            if (list.get(i).getValue() > list.get(max).getValue()) {
                max = i;
            }
        }
        return max;
    }

    /**
     * Returns the sum of the values of the elements.
     * @param list list of elements to be summed
     */
    public double valuesSum (List<Element> list) {
        double sum = 0;
        for (Element e : list) {
            sum += e.getValue();
        }
        return sum;
    }

    /**
     * Generates the data required to create a bubble.
     */
    public List<Integer> generateDataForBubble () {
        return new ArrayList<Integer>();
    }

    /**
     * Returns a list of stock prices for a data set.
     * 
     * @param name name of the data set
     */ 
    public List<Integer> getElementData (String name) {
        List<Integer> stockData = new ArrayList<Integer>();
        for (Element e : myEls) {
            if (e.getName().equals(name)) {
                List<Double> valueListCopy = new ArrayList<Double>(e.getValueList());
                return Calculator.doubleToIntegerList(valueListCopy);
            }
        }
        return stockData;
    }
}
